package smartclass.bianor.local;

import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;

import java.util.Enumeration;


public class SerialComunication implements SerialPortEventListener {
	
	
	/*
	 * action: Variável de controle, para saber se são comandos diferentes. Ex:
	 * Ligar lampada: action = 1
	 * Desligar lampada: action = 0
	 * 
	 * Usando essa variavel foi feita uma lógica de modo que um comando de ligar não é
	 * enviado após outro comando de ligar. Isso é feito pois não precisamos mandar
	 * ligar uma lampâda que já esta ligada
	 * 
	 * 
	 * 
	 * */
	
	/*
	 * dados[]: Onde são guardados os dados recebidos. Como eu sei que o tamanho do vetor é 18? 
	 * Através de um teste. Enviei um pacote do arduino e criei um programinha para imprimir tudo
	 * que chegar pela serial. Desse jeito eu vi o tamanho dos pacotes
	 * 
	 * 
	 * */
	
	
	
	
	int action = 0;
	SerialPort serialPort;
	int dados[] = new int[18]; 


	private static final String PORT_NAMES[] = { "COM6" }; // Porta Usada
	// private static final String PORT_NAMES[] = { "/dev/tty.usbmodem411" }; //
	

	private static BufferedReader input;
	private static OutputStream output;
	private static final int TIME_OUT = 2000; // Milissegundos para bloqueio
												// enquanto aguarda a porta
												// abrir

	private static final int DATA_RATE = 9600; // baud rate da porta

	public void initialize() {
		CommPortIdentifier portId = null;
		Enumeration<?> portEnum = CommPortIdentifier.getPortIdentifiers();

		while (portEnum.hasMoreElements()) {
			CommPortIdentifier currPortId = (CommPortIdentifier) portEnum
					.nextElement();
			for (String portName : PORT_NAMES) {
				if (currPortId.getName().equals(portName)) {
					portId = currPortId;
					break;
				}
			}
		}
		if (portId == null) {
			System.out.println("\nPorta COM nao encontrada\n");
			return;
		}

		try {
			serialPort = (SerialPort) portId.open(this.getClass().getName(),
					TIME_OUT);

			serialPort.setSerialPortParams(DATA_RATE, SerialPort.DATABITS_8,
					SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

			input = new BufferedReader(new InputStreamReader(
					serialPort.getInputStream(),"ISO-8859-1"));         // Mudança de codificação padrão UTF-8 ( -127 a 127) para 
			serialPort.addEventListener((SerialPortEventListener) this);// ISO-8859-1 (0 a 255), pois o xbee envia de 0 a 255,
																		// logo eu tenho que ler de 0 a 255
			serialPort.notifyOnDataAvailable(true);
		} catch (Exception e) {
			System.err.println(e.toString());
		}
	}

	/**
	 * Deve ser chamado quando voc� parar de usar a porta. Evita travamento de
	 * porta em plataformas Linux.
	 */
	public synchronized void close() {
		if (serialPort != null) {
			serialPort.removeEventListener();
			serialPort.close();
		}
	}

	public synchronized void serialEvent(SerialPortEvent oEvent) {
		
		if (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
			
			
			try {
				
				/*
				 * aqui eu leio cada byte que ta do buffreader. 126 sempre eh o primeiro byte
				 * do pacote, por isso eu só começo a guardar os dados no vetor quando eu acho 
				 * o 126. A informação útil do vetor será o data[15](temperatura) e o 
				 * data[16] luminosidade. As outras casas do vetor são informações de protocolo,
				 * cabe salientar que eu recebo o endereço de quem me mando a mensagem que fica nas 
				 * casas dados[5] até dados[11]. 
				 * 
				 * Aqui no caso eu estou fazendo o tratamendo da luminosidade, caso ela fique < 80
				 * eu mando ligar a luz, senão fica apagada e faço aquela logica para não mandar
				 * ligar uma coisa que já está ligada ou desligar uma coisa que já está desligada.
				 * 
				 * Esse 80 da luz vem de uma normalizaçao que eu fuz no arduino, o xbee nao deixa 
				 * enviar dados maiores que 255 em um unico espaço do vetor. O range do ldr é 
				 * 0 - 1023. Ae como faz pra eu enviar isso pelo xbee? Eu podia quebrar em parte alta
				 * e baixa e enviar em 2 casas o número, mas como eu quis simplificar ao máximo lá no
				 * arduino, fiz uma normalização do range 0 - 1023 para 0 - 255, claro que eu perco
				 * precisão com isso, mas isso NO MOMENTO pode ser desprezado.
				 * 
				 * 
				 * */
	
				int singleData =  input.read();			
				if (singleData == 126) {
					
					dados[0] = singleData;
					for(int i=1;i<dados.length;i++) {
						dados[i] = input.read();
						
					}
					
					System.out.println(dados[16]);
					if (dados[16] < 80) {

						if(action != 1) {
							
							action = 1;
							enviar(1);						
						}
	
					} else {
						
						if(action != 0) {
							action = 0;
							enviar(0);
						
						}
						
					}
					
					
				}
				

			} catch (Exception e) {
				System.err.println(e.toString());
			}
		}

	}
	
	/* Método para enviar um dado ao arduino, UM DADO, digo isso porque caso você queira mandar
	 * mais de um, você terá que alterar o número desta sequÊncia que indica quantos bits são enviados.
	 * Alterando este número vc altera a posição do checksum e resumindo, nada é enviado. Eu sei,
	 * este código não está nada genérico :(
	 * 
	 * Pelo menos o calculo do valor do checksum é genérico, a fórmula tem no livro do Faludi sobre Xbee
	 * e tem também na net, só dá uma procurada.
	 * 
	 * 
	 * */
	
	
	public void enviar(int a) {
		
		try {
			
			output = serialPort.getOutputStream();
			
			int soma = 0;
			int checksum = 0;
			int dat[]={0x7E,0x00,15,0x10,0x00,0x00,0x13,0xA2,0x00,0x40,0xA9,0xC4,0xFC,0xFF,0xFE,0,0,a,113};
			
			for (int i = 3; i < ((dat.length) - 1); i++) {
				soma = soma + dat[i];
			}
			
			soma = soma % 256;
			checksum = 0xFF - soma;
			dat[18] = checksum;
			
			for (int i = 0; i <dat.length; i++) {
				output.write(dat[i]);	
			}
	
		
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	public static void main(String[] args) {
		
		SerialComunication app = new SerialComunication();
		app.initialize();

	}
}
